package com.hxzy.common.aspect;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.hxzy.common.annon.Log;
import com.hxzy.common.util.ChinazWebUtil;
import com.hxzy.common.util.ServletUtils;
import com.hxzy.common.util.UserAgentUtil;
import com.hxzy.entity.SysOperLog;
import com.hxzy.service.SysOperLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * 日志增强操作(AOP)
 * 增强位置： @Before 前置， @AfterReturing 后置返回值    @After后置，  @AfterThrowing异常，@Around环绕
 * 操作成功记录 @AfterReturing
 * 操作失败记录 @AfterThrowing
 */
@Aspect
@Component
public class LogAspect {

    @Autowired
    private SysOperLogService sysOperLogService;

    //定义连接点 PointCut
    // 对所有的Controller中的方法都要进行日志记录，我们的要求是只针对 新增，修改，删除操作，以下的方案不合适
    //@Pointcut(value = "execution(* com.hxzy.controller..*.*(..))")
    @Pointcut(value = "@annotation(com.hxzy.common.annon.Log)")
    private void pointCutExpression(){
    }

    /**
     * 操作成功记录
     * @param jp
     * @param log
     * @param retVal
     */
    @AfterReturning(pointcut="pointCutExpression() && @annotation(log)",  returning="retVal")
    public void successAdvice(JoinPoint jp, Log log, Object retVal) throws JsonProcessingException {
        writerToDataBase(jp,log,retVal,null);
    }

    /**
     * 操作失败的记录
     * @param jp
     * @param log
     * @param ex
     */
    @AfterThrowing(pointcut="pointCutExpression() && @annotation(log)", throwing="ex")
    public void errorAdvice(JoinPoint jp, Log log, Exception ex) throws JsonProcessingException {

        writerToDataBase(jp,log,null,ex);
    }


    /**
     * 把日志写入到数据库中
     * @param jp
     * @param log
     * @param retVal
     * @param ex
     */
    private void writerToDataBase(JoinPoint jp,Log log, Object retVal,Exception ex) throws JsonProcessingException {

        SysOperLog sysOperLog=new SysOperLog();
        //操作模块
        sysOperLog.setTitle( log.title().getName());
        //操作类型
        sysOperLog.setBusinessType(log.businessType().getId());
        //类+方法
        sysOperLog.setMethod( jp.getSignature().toLongString());
        //参数
        Object[] params=jp.getArgs();
        ObjectMapper  objectMapper=new ObjectMapper();
        String paramsString = objectMapper.writeValueAsString(params);
        sysOperLog.setOperParam(paramsString);
        sysOperLog.setOperTime(new Date());


        // 没有异常,记录返回结果
        if(ex==null){
            if(retVal!=null){
                String objectJson=objectMapper.writeValueAsString(retVal);
                sysOperLog.setJsonResult(objectJson);
            }
            sysOperLog.setStatus(0);
        }else{
            sysOperLog.setErrorMsg(StrUtil.sub(ex.getMessage(),0,500)  );
            sysOperLog.setStatus(1);
        }

        //还差HttpServletRequest中才能取 String method;  String operUrl;  String operName;   String operIp;  String operLocation;
        // SpringWeb框架能否获取当前请求的HttpServletRequest对象 ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletRequest  request= ServletUtils.getRequest();
        //本次请求方式
        sysOperLog.setRequestMethod( request.getMethod());
         //请求url
        sysOperLog.setOperUrl( request.getRequestURI());
        //请求IP(局网的IP)
        sysOperLog.setOperIp(request.getRemoteAddr());

        //用户在哪里,只能获取广域网IP，查询它在哪里
        String[] arr= ChinazWebUtil.getIpAndCity();
        sysOperLog.setOperLocation(arr[1]);

        /** 操作类别（0其它 1后台用户 2手机端用户） ,根据用户登录以后才能决定*/
        sysOperLog.setOperatorType(1);

        //写入到数据库中
        this.sysOperLogService.save(sysOperLog);
    }

}
